<?php

namespace App\Helpers;

/**
 * 工具类
 * @package App\Helpers
 */
class Utils {

    /**
     * Returns the specified config item
     *
     * @access    public
     * @return    mixed
     */
    static function configItem($item) {
        static $configItem = array();
        if (!isset($configItem[$item])) {
            /**
             * 读取配置文件
             */
            $config = \Phalcon\DI::getDefault()->getShared("config");;

            if (!isset($config[$item])) {
                return FALSE;
            }
            $configItem[$item] = $config[$item];
        }
        return $configItem[$item];
    }

    /**
     * 对象转数组
     *
     * We use this as a simple mechanism to access the logging
     * class and send messages to be logged.
     *
     * @access    public
     * @return    void
     */
    static function objectToArray($array) {
        if (is_object($array)) {
            $array = (array)$array;
        }
        if (is_array($array)) {
            foreach ($array as $key => $value) {
                $array[$key] = self::objectToArray($value);
            }
        }
        return $array;
    }

    /**
     * 生成短信验证码
     * @param $min 最小值
     * @param $max 最大值
     * @return int
     */
    static function generateSmsCode($min, $max) {
        return rand($min, $max);
    }

    /**
     * 读取响应数据配置数组
     * @param string $fileName 文件名称
     * @param string $ver 版本文件夹
     * @return array
     */
    static function readLanguage($fileName = "responseCode", $ver = "") {
        $dir = Utils::configItem("lang");
        if ($ver) {
            $ver = "/modules/{$ver}/";
        }
        return include APP_PATH . "/app/{$ver}language/{$dir}/{$fileName}.php";
    }

    /**
     * 数组按key的顺序排序
     * @param $arr
     * @return 排序后的数组
     */
    static function arraySort(array $arr) {
        ksort($arr);
        reset($arr);
        return $arr;
    }

    /**
     * 数组按key的倒序排序
     * @param $arr
     * @return 排序后的数组
     */
    static function arrayRSort(array $arr) {
        krsort($arr);
        reset($arr);
        return $arr;
    }

    /**
     * 把数组所有元素，按照“参数=参数值”的模式用“&”字符拼接成字符串
     *
     * @param $arr 需要拼接的数组
     * @return string 拼接完成以后的字符串
     */
    static function generateArrayString($arr) {
        $str = "";
        foreach ($arr as $key => $val) {
            $str .= "{$key}={$val}&";
        }
        // 去掉最后一个&字符
        $str = substr($str, 0, count($str) - 2);
        return $str;
    }

    /**
     * 获取随机字符串
     * @param int $len
     * @return string
     */
    static function getRandChar($len = 6) {
        $chars = array(
            "Q", "W", "E", "R", "T", "Y", "U", "I", "O", "P", "A", "S", "D", "F", "G", "H", "J", "K", "L", "Z", "X", "C", "V", "B", "N", "M",
            "q", "w", "e", "r", "t", "y", "u", "i", "o", "p", "a", "s", "d", "f", "g", "h", "j", "k", "l", "z", "x", "c", "v", "b", "n", "m",
            "1", "2", "3", "4", "5", "6", "7", "8", "9", "0"
        );
        $char = "";
        $numChars = count($chars) - 1;
        for ($i = 0; $i < $len; $i++)
            $char .= $chars [rand(0, $numChars)];
        return $char;
    }

    /**
     * 生成Token
     * @param string $suffix Token后缀
     * @param int $len 长度
     * @return string
     */
    static function getRandMd5String($suffix, $len = 32) {
        $seed = (double)microtime() * 1000000;
        mt_srand($seed);
        $chars = array(
            'Q', '@', '8', 'y', '%', '^', '5', 'Z', '(', 'G', '_', 'O', '`',
            'S', '-', 'N', '<', 'D', '{', '}', '[', ']', 'h', ';', 'W', '.',
            '/', '|', ':', '1', 'E', 'L', '4', '&', '6', '7', '#', '9', 'a',
            'A', 'b', 'B', '~', 'C', 'd', '>', 'e', '2', 'f', 'P', 'g', ')',
            '?', 'H', 'i', 'X', 'U', 'J', 'k', 'r', 'l', '3', 't', 'M', 'n',
            '=', 'o', '+', 'p', 'F', 'q', '!', 'K', 'R', 's', 'c', 'm', 'T',
            'v', 'j', 'u', 'V', 'w', ',', 'x', 'I', '$', 'Y', 'z', '*'
        );
        // Array indice friendly number of chars;
        $numChars = count($chars) - 1;
        $str = '';
        // Create random token at the specified length
        for ($i = 0; $i < $len; $i++)
            $str .= $chars [mt_rand(0, $numChars)];
        // Number of 32 char chunks
        $chunks = ceil(strlen($str) / 32);
        $md5 = '';
        // Run each chunk through md5
        for ($i = 1; $i <= $chunks; $i++)
            $md5 .= md5($suffix . $seed . substr($str, $i * 32 - 32, 32));
        // Trim the token
        return substr($md5, 0, $len);
    }

    /**
     * 获得当前时间的毫秒数
     * @return float
     */
    static function getMillisecond() {
        list($t1, $t2) = explode(' ', microtime());
        return (float)((floatval($t1) + floatval($t2)) * 1000) / 1000;
    }

    /** 格式化时间戳，精确到毫秒，x代表毫秒 */

    /**
     * 式化时间戳，精确到毫秒，x代表毫秒
     * @param string $format 时间格式
     * @param int time 时间戳
     * @return mixed
     */
    static function microTimeFormat($format = "YmdHisx", $time = 0) {
        if (!$time)
            $time = self::getMillisecond();
        list($usec, $sec) = explode(".", $time);
        $date = date($format, $usec);
        return str_replace('x', $sec, $date);
    }

    /**
     * 字符串格式化
     *
     * @return string
     */
    static function stringFormat() {
        $args = func_get_args();
        if (count($args) == 0) {
            return;
        }
        if (count($args) == 1) {
            return $args[0];
        }
        if (count($args) == 2 && is_array($args[1])) {
            $str = $args[0];
            $args = $args[1];
        } else {
            $str = array_shift($args);
        }

        $str = preg_replace_callback('/\\{(0|[1-9]\\d*)\\}/', create_function('$match', '$args = ' . var_export($args, true) . '; return isset($args[$match[1]]) ? $args[$match[1]] : $match[0];'), $str);
        return $str;
    }

    /**
     * 将数组转换成XML
     * @param $arr 数组
     * @return string xml字符串
     */
    static function arrayToXml($arr) {
        $xml = "<xml>";
        foreach ($arr as $key => $val) {
            $xml .= self::_createNode($key, $val);
        }
        $xml .= "</xml>";
        return $xml;
    }

    /**
     * 根据键、值创建XML节点
     * @param $key 键
     * @param $val 值
     * @return string
     */
    private static function _createNode($key, $val) {
        $xml = "<{$key}>";
        if (is_array($val)) {
            foreach ($val as $k => $v) {
                $xml .= self::createNode($k, $v);
            }
        } elseif (is_numeric($val)) {
            $xml .= "{$val}";
        } else {
            $xml .= "<![CDATA[{$val}]]>";
        }
        $xml .= "</{$key}>";
        return $xml;
    }

    /**
     * 将XML字符串转换成数组
     * @param $xml
     * @return mixed
     */
    static function xmlToArray($xml) {
        //禁止引用外部xml实体
        libxml_disable_entity_loader(true);
        $values = json_decode(json_encode(simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA)), true);
        return $values;
    }

    /**
     * 获得所有请求头信息
     * @return mixed
     */
    static function getAllHeaders() {
        static $headers;
        if (!isset($headers)) {
            if (function_exists("getallheaders")) {
                $headers = getallheaders();
            } else {
                foreach ($_SERVER as $name => $value) {
                    if (substr($name, 0, 5) == 'HTTP_') {
                        if ($name == "HTTP_WWW_AUTHENTICATE") {
                            $key = "Authorization";
                        } else {
                            $key = str_replace(' ', '-', ucwords(strtolower(str_replace('_', ' ', substr($name, 5)))));
                        }
                        $headers[$key] = $value;
                    } elseif (isset($_SERVER['PHP_AUTH_DIGEST'])) {
                        $headers['Authorization'] = $_SERVER['PHP_AUTH_DIGEST'];
                    } elseif (isset($_SERVER['PHP_AUTH_USER']) || isset($_SERVER['PHP_AUTH_PW'])) {
                        if (isset($_SERVER['PHP_AUTH_USER']) && $_SERVER['PHP_AUTH_USER']
                            && isset($_SERVER['PHP_AUTH_PW']) && $_SERVER['PHP_AUTH_PW']
                        ) {
                            $headers['Authorization'] = base64_encode($_SERVER['PHP_AUTH_USER'] . ':' . $_SERVER['PHP_AUTH_PW']);
                        } elseif (isset($_SERVER['PHP_AUTH_USER'])) {
                            $headers['Authorization'] = $_SERVER['PHP_AUTH_USER'];
                        }
                    } elseif (isset($_SERVER['CONTENT_LENGTH'])) {
                        $headers['content-length'] = $_SERVER['CONTENT_LENGTH'];
                    } elseif (isset($_SERVER['CONTENT_TYPE'])) {
                        $headers['content-type'] = $_SERVER['CONTENT_TYPE'];
                    } else {
                        $headers[$name] = $value;
                    }
                }
            }
        }
        return $headers;
    }

    /**
     * 根据空间名称获取媒体的完整Url
     * @param $path 相对路径
     * @param string $bucket 空间名称
     * @return string
     */
    static function getMediaUrl($path, $bucket = "image") {
        if ($path && strpos($path, "http://") === false && strpos($path, "https://") === false) {
            switch ($bucket) {
                case "image":
                    $host = \Qiniu\QiniuClient::getImageHost();
                    break;
                case "media":
                    $host = \Qiniu\QiniuClient::getMediaHost();
                    break;
                case "preOrder":
                case "course":
                    $host = \Qiniu\QiniuClient::getBucketHost($bucket);
                    break;
                default:
                    $host = "/";
            }
            return $host . $path;
        }
        return $path;
    }

    /**
     * 直播直播封面的完整Url
     * @param $path 相对路径
     * @return string
     */
    static function getLiveCoverUrl($path) {
        if ($path && strpos($path, "http://") === false && strpos($path, "https://") === false) {
            return \Qiniu\QiniuClient::getLiveCoverHost() . $path;
        }
        return $path;
    }

    /**
     * 回放的完整URL
     * @param $path 相对路径
     * @return string
     */
    static function getReplayUrl($path) {
        if ($path && strpos($path, "http://") === false && strpos($path, "https://") === false) {
            return \Qiniu\QiniuClient::getReplayHost() . \Qiniu\QiniuClient::REPLAY_PREFIX . "/{$path}/" . \Qiniu\QiniuClient::REPLAY_FILENAME;
        }
        return $path;
    }

    /**
     * 获取日期的增量格式
     * @param $len 时长
     * @param $unit 单位（0：天；1：月；2：年）
     * @return string
     */
    static function getDateIncrFormat($len, $unit) {
        // 单位
        switch ($unit) {
            case "0":
                return "{$len} day";
            case "1":
                return "{$len} month";
            case "2":
                return "{$len} year";
            default:
                return "{$len} hours";
        }
    }

    /**
     * 获取时间差
     * @param $startTime 开始时间
     * @param $endTime 结束时间
     * @param string $format 格式（年（y），月（m）,日(d),时(H),分(i),秒(s)）
     * @return int
     */
    static function getDateDiff($startTime, $endTime, $format = "d") {
        $second = strtotime($endTime) - strtotime($startTime);
        switch ($format) {
            case "s":
                return $second;
            case "i":
                return ceil($second / 60);
            case "H":
                return ceil($second / 3600);
            case "d":
                return ceil($second / 86400);
            case "m":
                return intval(date("m", $endTime)) - intval(date("m", $startTime));
            case "y":
                return intval(date("y", $endTime)) - intval(date("y", $startTime));
        }
    }

    /**
     * 解析有@格式的字符串
     * @param $str 文本信息
     * @return array 解析后的@数据
     */
    static function parseAtFormatStr($str) {
        // 正则表达式字符串
        $pattern = '(<at user_id="(.*)">(.*)</at>)';

        $arr = explode("</at>", $str);
        // @列表
        $ats = array();
        foreach ($arr as $str) {
            $str .= "</at>";
            // 匹配的结果数组
            $matches = array();
            // 全局正则表达式匹配
            preg_match_all($pattern, $str, $matches);
            if ($matches && count($matches) == 3) {
                $idArr = $matches[1];       // @的编号列表
                $nameArr = $matches[2];     // @的名称列表
                $idArrCount = count($idArr);        // @的编号列表长度
                $nameArrCount = count($nameArr);    // @的名称列表长度
                // 如果两个列表的长度都为0，则表示文本中没有@数据
                if ($idArrCount && $nameArrCount) {
                    $count = $idArrCount >= $nameArrCount ? $nameArrCount : $idArrCount;
                    for ($i = 0; $i < $count; $i++) {
                        $ats[$idArr[$i]] = $nameArr[$i];
                    }
                }
            }
        }
        return $ats;
    }

    /**
     * 清空@格式的字符
     * @param $str 文本信息
     * @return string 清空了@格式后字符串
     */
    static function clearAtFormatStr($str) {
        // 正则表达式字符串
        $pattern = '(<at user_id="(.*)">(.*)</at>)';
        // 全局正则表达式匹配
        return preg_replace($pattern, "", $str);
    }

    /**
     * 解析没有@格式的字符串
     * @param $str 文本信息
     * @return array 解析后的@数据
     */
    static function parseUnAtFormatStr($str) {
        // 正则表达式字符串
        $pattern = '(@(\S*))';
        // 匹配的结果数组
        $matches = array();
        // 全局正则表达式匹配
        preg_match_all($pattern, $str, $matches);

        // @列表
        return $matches && count($matches) == 2 && $matches[1] ? $matches[1] : FALSE;
    }

    /**
     * 设置非@格式的字符串
     * @param $str 文本信息
     * @param $ats @列表
     * @return string 清空了@格式后字符串
     */
    static function setUnAtFormatStr($str, $ats) {
        $str .= " ";
        foreach ($ats as $id => $name) {
            $replace = '<at user_id="' . $id . '">' . $name . '</at> ';
            $str = str_replace("{$name} ", $replace, $str);
        }
        return rtrim($str, " ");
    }

    /**
     * 解析有话题格式的字符串
     * @param $str 文本信息
     * @return array 解析后的话题数据
     */
    static function parseTopicFormatStr($str) {
        // 正则表达式字符串
        $pattern = '(#[^#]+#)';
        // 匹配的结果数组
        $matches = array();
        // 全局正则表达式匹配
        preg_match_all($pattern, $str, $matches);

        // @列表
        return $matches ? $matches[0] : FALSE;
    }

    /**
     * 解析没有话题格式的字符串
     * @param $str 文本信息
     * @return array 解析后的话题数据
     */
    static function parseUnTopicFormatStr($str) {
        // 正则表达式字符串
        $pattern = '(#[^#]+#)';
        // 匹配的结果数组
        $matches = array();
        // 全局正则表达式匹配
        preg_match_all($pattern, $str, $matches);

        $topics = array();
        if ($matches) {
            foreach ($matches[0] as $topic) {
                $topics[] = str_replace("#", "", $topic);
            }
        }
        // 话题列表
        return $topics;
    }

    /**
     * 转化为弧度(rad)
     * @param $value 经纬度的值
     * @return float
     */
    static function rad($value) {
        return floatval($value * pi() / 180.0);
    }

    /**
     * 计算两个点之间的距离
     * @param $point1 点1
     * @param $point2 点2
     * @return float
     */
    static function latitudeLongitudeDist($point1, $point2) {
        $earthRadius = 6378137.00;//赤道半径(单位m) ;
        $point1["longitude"] = self::rad($point1["longitude"]); // 经度
        if ($point1["longitude"] < 0) {
            $point1["longitude"] = floatval(pi() / 2.0 - abs($point1["longitude"]));// west
        }
        $point1["latitude"] = self::rad($point1["latitude"]);   // 纬度
        if ($point1["latitude"] < 0) {
            $point1["latitude"] = pi() / 2.0 + abs($point1["latitude"]);// south
        } elseif ($point1["latitude"] > 0) {
            $point1["latitude"] = pi() * 2.0 - abs($point1["latitude"]);// north
        }
        $x1 = $earthRadius * cos($point1["longitude"]) * sin($point1["latitude"]);
        $y1 = $earthRadius * sin($point1["longitude"]) * sin($point1["latitude"]);
        $z1 = $earthRadius * cos($point1["latitude"]);

        $point2["longitude"] = self::rad($point2["longitude"]); // 经度
        if ($point2["longitude"] < 0) {
            $point2["longitude"] = pi() / 2.0 - abs($point2["longitude"]);// west
        }
        $point2["latitude"] = self::rad($point2["latitude"]);   // 纬度
        if ($point2["latitude"] < 0) {
            $point2["latitude"] = pi() / 2.0 + abs($point2["latitude"]);// south
        } elseif ($point2["latitude"] > 0) {
            $point2["latitude"] = pi() * 2.0 - abs($point2["latitude"]);// north
        }
        $x2 = $earthRadius * cos($point2["longitude"]) * sin($point2["latitude"]);
        $y2 = $earthRadius * sin($point2["longitude"]) * sin($point2["latitude"]);
        $z2 = $earthRadius * cos($point2["latitude"]);

        $d = abs(sqrt(($x1 - $x2) * ($x1 - $x2) + ($y1 - $y2) * ($y1 - $y2) + ($z1 - $z2) * ($z1 - $z2)));
        //余弦定理求夹角
        $theta = floatval(acos(($earthRadius * $earthRadius + $earthRadius * $earthRadius - $d * $d) / (2 * $earthRadius * $earthRadius)));
        $dist = floatval($theta * $earthRadius);
        return $dist;
    }
}

